Skip to content

View guestbook and download file with guestbook#926

Open
ChengShi-1 wants to merge 12 commits intodevelopfrom
896-add-terms-of-use-and-guestbook-to-file-download
Open

View guestbook and download file with guestbook#926
ChengShi-1 wants to merge 12 commits intodevelopfrom
896-add-terms-of-use-and-guestbook-to-file-download

Conversation

@ChengShi-1
Copy link
Contributor

@ChengShi-1 ChengShi-1 commented Mar 2, 2026

What this PR does / why we need it:

Which issue(s) this PR closes:

Special notes for your reviewer:

  • wait js-dataverse to be merged
  • In the DownloadwithGuestbookModal, the name&email fields are not editable for login users (we discussed in weekly meeting March 5th)

Suggestions on how to test this:

For the modal of Dataset Terms, which means to collect users' response before downloading files.

If the guestbook is selected, the dataset should show the modal of Dataset Terms in the following pages

  • In Dataset Page, "Access Dataset" -> "Download Options"
image
  • In Dataset Page, under the File tab, if you (1) select multiple files or (2) download one file
image image - In File page, "Access Dataset" Button -> "Download Options" image - The Dataset Terms modal should work well, and should show both terms and guestbook info (prefilled if there is a login user) image

For the Guestbook Info
Terms and Guestbook tab, Guestbook info should be shown(if it's empty, it will show different text)
image
Edit Guestbook should work correctly(if it's empty, it will show different text)
image
Preview Guestbook Modal should work correctly
image

Does this PR introduce a user interface change? If mockups are available, please link/include them here:

Is there a release notes or changelog update needed for this change?:

Additional documentation:

@ChengShi-1 ChengShi-1 linked an issue Mar 2, 2026 that may be closed by this pull request
@github-actions github-actions bot added FY26 Sprint 17 FY26 Sprint 17 (2026-02-11 - 2026-02-25) FY26 Sprint 18 FY26 Sprint 18 (2026-02-25 - 2026-03-11) GREI Re-arch GREI re-architecture-related Project: HDV SPA Rollout SPA labels Mar 2, 2026
@coveralls
Copy link

coveralls commented Mar 2, 2026

Coverage Status

coverage: 97.496% (+0.1%) from 97.347%
when pulling 983268d on 896-add-terms-of-use-and-guestbook-to-file-download
into 94aecb3 on develop.

@ChengShi-1 ChengShi-1 self-assigned this Mar 5, 2026
@ChengShi-1 ChengShi-1 moved this to In Progress 💻 in IQSS Dataverse Project Mar 5, 2026
@ChengShi-1 ChengShi-1 marked this pull request as ready for review March 6, 2026 21:40
@ChengShi-1 ChengShi-1 added the Size: 20 A percentage of a sprint. 14 hours. label Mar 9, 2026
@ChengShi-1 ChengShi-1 requested a review from Copilot March 10, 2026 14:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Implements guestbook-aware dataset/file downloads and adds UI to view/edit guestbook configuration, aligning the frontend with Dataverse’s guestbook + terms-of-use download flow (Issue #896) and updated js-dataverse APIs.

Changes:

  • Add guestbook domain/repository layer + hooks, plus UI for previewing and editing guestbooks in “Edit Dataset Terms”.
  • Introduce a “Download with Guestbook” modal and wire it into dataset downloads, multi-file downloads, and file download menus.
  • Map guestbookId from API models into dataset/file domain models and bump @iqss/dataverse-client-javascript.

Reviewed changes

Copilot reviewed 91 out of 92 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
tests/e2e-integration/shared/guestbooks/GuestbookHelper.ts Adds e2e API helper for creating/listing/assigning guestbooks.
tests/component/sections/session/SessionProvider.spec.tsx Expands session-loading/error tests and adds token-missing behaviors.
tests/component/sections/layout/header/Header.spec.tsx Removes focused it.only from notifications test.
tests/component/sections/guestbooks/useGetGuestbooksByCollectionId.spec.tsx Adds hook tests for fetching guestbooks by collection.
tests/component/sections/file/file-action-buttons/access-file-menu/FileTabularDownloadOptions.spec.tsx Updates tests for new props/locked state handling.
tests/component/sections/file/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.spec.tsx Updates tests for new props/locked state handling.
tests/component/sections/edit-dataset-terms/useUpdateTermsOfAccess.spec.tsx Adjusts WriteError formatting expectations using handler.
tests/component/sections/edit-dataset-terms/useGetLicenses.spec.tsx Adds tests for license hook including error formatting.
tests/component/sections/edit-dataset-terms/useAssignDatasetGuestbook.spec.tsx Adds tests for assigning dataset guestbook.
tests/component/sections/edit-dataset-terms/EditTermsOfAccess.spec.tsx Adds loading/navigation-related tests and draft/released cancel routing checks.
tests/component/sections/edit-dataset-terms/EditLicenseAndTerms.spec.tsx Adds “dataset not loaded” and cancel-navigation coverage.
tests/component/sections/edit-dataset-terms/EditGuestbook.spec.tsx Adds comprehensive tests for the new guestbook edit tab UI.
tests/component/sections/edit-dataset-terms/EditDatasetTerms.spec.tsx Integrates guestbook tab + tab query param parsing tests.
tests/component/sections/dataset/dataset-versions/useGetDatasetVersionDiff.spec.tsx Fixes stub shape + async waiting.
tests/component/sections/dataset/dataset-terms/DatasetTerms.spec.tsx Adds guestbook accordion coverage and query-param auto-open behavior.
tests/component/sections/dataset/dataset-files/guestbook/useGetGuestbookById.spec.tsx Adds hook tests for fetching a guestbook by id.
tests/component/sections/dataset/dataset-files/guestbook/DownloadWithGuestbookModal.spec.tsx Adds modal tests: validation, custom questions, authenticated behavior.
tests/component/sections/dataset/dataset-files/files-table/.../useGuestbookAppliedSubmission.spec.tsx Adds tests for guestbook submission hook and download triggering.
tests/component/sections/dataset/dataset-files/files-table/file-actions/download-files/DownloadFilesButton.spec.tsx Adds tests ensuring guestbook modal opens/submits for selected files.
tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/delete-draft-dataset/useDeleteDraftDataset.spec.tsx Adds tests for delete-draft hook + error formatting.
tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeaccessionDatasetButton.spec.tsx Expands render/propagation/cancel modal tests.
tests/component/sections/dataset/dataset-action-buttons/access-dataset-menu/AccessDatasetMenu.spec.tsx Adds guestbook-modal behaviors and download-size edge cases.
tests/component/sections/dataset/dataset-action-buttons/DatasetToolOptions.spec.tsx Adds resolved URL call assertions and popup-closed error handling test.
tests/component/sections/dataset/dataset-action-buttons/DatasetActionButtons.spec.tsx Updates expectations for Access Dataset button rendering.
tests/component/sections/dataset/Dataset.spec.tsx Asserts guestbook section exists on Terms tab.
tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts Adds coverage for mapping guestbookId.
tests/component/dataset/domain/models/DatasetMother.ts Updates dataset mother builder to include guestbookId.
src/stories/guestbooks/preview-modal/PreviewGuestbookModal.stories.tsx Adds story for previewing guestbook modal.
src/stories/guestbooks/guestbook-applied-modal/DownloadWithGuestbookModal.stories.tsx Adds story for download modal with guestbook submission.
src/stories/edit-dataset-terms/EditDatasetTerms.stories.tsx Updates guestbook tab story naming/key.
src/stories/dataset/dataset-terms/DatasetTerms.stories.tsx Adds guestbook-aware DatasetTerms stories/decorators.
src/stories/dataset/dataset-guestbook/DatasetGuestbook.stories.tsx Adds stories for dataset guestbook section states.
src/sections/guestbooks/useGetGuestbooksByCollectionId.tsx New hook for listing guestbooks per collection.
src/sections/guestbooks/preview-modal/PreviewGuestbookModal.tsx New preview modal UI for guestbook collected fields/questions.
src/sections/guestbooks/GuestbookRepositoryProvider.tsx Adds provider for guestbook repository.
src/sections/guestbooks/GuestbookRepositoryContext.ts Adds context + default JS-Dataverse repository.
src/sections/file/file-action-buttons/access-file-menu/FileTabularDownloadOptions.tsx Adds guestbook modal interception for tabular file downloads.
src/sections/file/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.tsx Adds guestbook modal interception for non-tabular file downloads.
src/sections/file/file-action-buttons/access-file-menu/FileDownloadOptions.tsx Passes dataset-derived guestbook/license/custom terms into file download options.
src/sections/file/file-action-buttons/access-file-menu/AccessFileMenu.tsx Wires fileId through to download options.
src/sections/file/FileFactory.tsx Wraps file page with Access/Guestbook repository providers.
src/sections/edit-dataset-terms/edit-guestbook/useAssignDatasetGuestbook.tsx New hook for assigning dataset guestbook via JS-Dataverse API.
src/sections/edit-dataset-terms/edit-guestbook/EditGuestbook.tsx Implements guestbook selection UI, preview, and submission flow.
src/sections/edit-dataset-terms/edit-guestbook/EditGuestbook.module.scss Styling for guestbook selection list and actions.
src/sections/edit-dataset-terms/edit-guest-book/EditGuestBook.tsx Removes old not-implemented guestbook tab.
src/sections/edit-dataset-terms/edit-guest-book/EditGuestBook.module.scss Removes old guestbook tab styling.
src/sections/edit-dataset-terms/EditDatasetTermsHelper.ts Renames tab key from guestBook to guestbook.
src/sections/edit-dataset-terms/EditDatasetTerms.tsx Enables guestbook tab content and updates keys/components.
src/sections/dataset/dataset-terms/DatasetTerms.tsx Adds guestbook accordion section and query-param auto-open.
src/sections/dataset/dataset-terms/DatasetTerms.module.scss Adds guestbook selection container styling.
src/sections/dataset/dataset-guestbook/useGetGuestbookById.ts New hook for fetching guestbook details by id.
src/sections/dataset/dataset-guestbook/DatasetGuestbook.tsx New dataset terms subsection to display assigned guestbook and preview.
src/sections/dataset/dataset-files/.../useGuestbookCollectSubmission.ts New hook to submit guestbook responses and trigger download.
src/sections/dataset/dataset-files/.../GuestbookCollectForm.tsx New form for terms/license + guestbook questions (incl. custom questions).
src/sections/dataset/dataset-files/.../DownloadWithGuestbookModal.tsx New modal that fetches guestbook, collects answers, submits, downloads.
src/sections/dataset/dataset-files/.../DownloadWithGuestbookModal.module.scss Styles for guestbook collection modal form.
src/sections/dataset/dataset-files/.../DownloadFilesButton.tsx Opens guestbook modal for multi-file downloads when guestbook assigned.
src/sections/dataset/dataset-action-buttons/access-dataset-menu/AccessDatasetMenu.tsx Opens guestbook modal for dataset ZIP downloads when guestbook assigned.
src/sections/dataset/dataset-action-buttons/DatasetActionButtons.tsx Passes guestbook/license/custom terms to access menu.
src/sections/dataset/DatasetFactory.tsx Wraps dataset page with Access/Guestbook repository providers.
src/sections/access/AccessRepositoryProvider.tsx Adds provider for access repository.
src/sections/access/AccessRepositoryContext.ts Adds context + default JS-Dataverse access repository.
src/info/domain/useCases/getTermsOfUse.ts Removes redundant catch/rethrow.
src/guestbooks/infrastructure/repositories/GuestbookJSDataverseRepository.ts Implements guestbook repository using JS-Dataverse client.
src/guestbooks/domain/useCases/getGuestbook.ts Adds guestbook retrieval use case.
src/guestbooks/domain/repositories/GuestbookRepository.ts Adds guestbook repository interface.
src/guestbooks/domain/models/Guestbook.ts Adds guestbook model definitions including custom questions/options.
src/files/infrastructure/mappers/JSFileMapper.ts Adds guestbookId/license/custom terms from dataset into File model.
src/files/domain/models/File.ts Extends File model with guestbookId/license/custom terms.
src/dataset/infrastructure/mappers/JSDatasetMapper.ts Maps guestbookId from API dataset model.
src/dataset/domain/useCases/updateTermsOfAccess.ts Removes redundant error wrapping.
src/dataset/domain/useCases/updateDatasetLicense.ts Removes redundant error wrapping.
src/dataset/domain/useCases/getDatasetVersionsSummaries.ts Removes redundant catch/rethrow.
src/dataset/domain/useCases/deleteDatasetDraft.ts Removes redundant catch/rethrow and unused import.
src/dataset/domain/models/Dataset.ts Adds guestbookId to Dataset + builder.
src/collection/domain/useCases/editCollection.ts Removes redundant catch/rethrow and unused import.
src/collection/domain/useCases/deleteCollection.ts Removes redundant catch/rethrow and unused import.
src/collection/domain/useCases/createCollection.ts Removes redundant catch/rethrow and unused import.
src/access/infrastructure/repositories/AccessJSDataverseRepository.ts Adds access repository implementation to submit guestbook responses.
src/access/domain/useCases/submitGuestbookForDatasetDownload.ts New use case wrapper.
src/access/domain/useCases/submitGuestbookForDatafilesDownload.ts New use case wrapper.
src/access/domain/useCases/submitGuestbookForDatafileDownload.ts New use case wrapper.
src/access/domain/repositories/AccessRepository.ts New access repository interface + answer type.
public/locales/es/files.json Adds Spanish strings for guestbook modal errors/validation.
public/locales/es/file.json Adds Spanish strings for guestbook modal errors/validation.
public/locales/es/dataset.json Adds Spanish “no guestbook assigned” string (partial guestbook i18n).
public/locales/en/guestbooks.json Adds guestbooks namespace strings for preview + collected data labels.
public/locales/en/files.json Adds guestbook modal error/validation strings.
public/locales/en/file.json Adds guestbook modal error/validation strings.
public/locales/en/dataset.json Adds guestbook terms tab strings + edit guestbook tab strings/errors.
package.json Bumps @iqss/dataverse-client-javascript to PR build.
package-lock.json Locks updated JS-Dataverse client version/resolution.
Comments suppressed due to low confidence (1)

public/locales/es/dataset.json:186

  • The Spanish locale only adds termsTab.noGuestbookAssigned, but the new guestbook UI also uses keys like termsTab.guestbookTitle, termsTab.guestbookTip, termsTab.guestbookDescription, and termsTab.guestbookPreviewButton (present in en/dataset.json). Add the missing Spanish translations for these new guestbook-related keys to avoid showing fallback keys in the UI.
  "termsTab": {
    "editTermsButton": "Editar requisitos de términos",
    "licenseTitle": "Términos del dataset",
    "termsTitle": "Ficheros restringidos + Términos de acceso",
    "licenseHelpText": "Nuestras <anchor>Normas de la comunidad</anchor> y las buenas prácticas científicas esperan que se den los créditos adecuados mediante la cita. Utiliza la cita de datos que se muestra en la página del dataset.",
    "restrictedFiles": "Ficheros restringidos",
    "termsOfAccess": "Términos de acceso para ficheros restringidos",
    "requestAccess": "Solicitar acceso",
    "dataAccessPlace": "Lugar de acceso a los datos",
    "originalArchive": "Fichero original",
    "availabilityStatus": "Estado de disponibilidad",
    "contactForAccess": "Contacto para acceso",
    "sizeOfCollection": "Tamaño de la colección",
    "studyCompletion": "Finalización del estudio",
    "termsOfUse": "Términos de uso",
    "termsOfUseTip": "Los términos de uso de este dataset.",
    "confidentialityDeclaration": "Declaración de confidencialidad",
    "specialPermissions": "Permisos especiales",
    "restrictions": "Restricciones",
    "citationRequirements": "Requisitos de citación",
    "depositorRequirements": "Requisitos del depositante",
    "conditions": "Condiciones",
    "disclaimer": "Descargo de responsabilidad",
    "confidentialityDeclarationTip": "Indica si se requiere firmar una declaración de confidencialidad para acceder a un recurso.",
    "specialPermissionsTip": "Determina si se requieren permisos especiales para acceder a un recurso (por ejemplo, si se necesita un formulario y dónde acceder a él).",
    "restrictionsTip": "Cualquier restricción de acceso o uso de la colección, como certificación de privacidad o restricciones de distribución, debe indicarse aquí. Pueden ser restricciones aplicadas por el autor, productor o difusor de la colección de datos. Si los datos están restringidos a solo una cierta clase de usuario, especifica cuál.",
    "citationRequirementsTip": "Incluye requisitos especiales/ explícitos de citación para que los datos sean citados correctamente en artículos u otras publicaciones basadas en el análisis de los datos. Para los requisitos estándar de citación consulta nuestras Normas de la comunidad.",
    "depositorRequirementsTip": "Información sobre la responsabilidad del usuario de informar a los depositantes del dataset, autores o curadores sobre su uso de los datos proporcionando citas a la obra publicada o copias de los manuscritos.",
    "conditionsTip": "Cualquier información adicional que ayude al usuario a comprender las condiciones de acceso y uso del dataset.",
    "disclaimerTip": "Información sobre la responsabilidad por los usos del dataset.",
    "restrictedFilesOne": "Hay 1 fichero restringido en este dataset.",
    "restrictedFilesMany": "Hay {{count}} ficheros restringidos en este dataset.",
    "termsOfAccessTip": "Información sobre cómo y si los usuarios pueden acceder a los ficheros restringidos en este dataset",
    "requestAccessTip": "Si está marcado, los usuarios pueden solicitar acceso a los ficheros restringidos en este dataset.",
    "requestAccessTrue": "Los usuarios pueden solicitar acceso a los ficheros.",
    "requestAccessFalse": "Los usuarios no pueden solicitar acceso a los ficheros.",
    "noGuestbookAssigned": "No hay un libro de visitas asignado a este dataset, por lo que no se pedirá a los usuarios que proporcionen información al descargar archivos. Para obtener más información sobre libros de visitas, visita la sección <anchor>Dataset Guestbook</anchor> de la Guía del usuario.",
    "restrictedFilesTip": "El número de ficheros restringidos en este dataset.",
    "dataAccessPlaceTip": "Si los datos no están solo en Dataverse, enumera la(s) ubicación(es) donde los datos están actualmente almacenados.",
    "originalArchiveTip": "Fichero del cual se obtuvieron los datos.",
    "availabilityStatusTip": "Declaración de disponibilidad del dataset. Un depositante puede necesitar indicar que un dataset no está disponible porque está embargado por un período de tiempo, porque ha sido reemplazado, porque una nueva edición es inminente, etc.",
    "contactForAccessTip": "Si es diferente del contacto del dataset, esta es la persona u organización de contacto (incluye correo electrónico o dirección completa, y número de teléfono si está disponible) que controla el acceso a una colección.",
    "sizeOfCollectionTip": "Resumen del número de ficheros físicos que existen en un dataset, registrando el número de ficheros que contienen datos y señalando si la colección contiene documentación legible por máquina y/u otros ficheros e información complementaria, como código, diccionarios de datos, declaraciones de definición de datos o instrumentos de recolección de datos.",
    "studyCompletionTip": "Relación de los datos recolectados con la cantidad de datos codificados y almacenados en el dataset. Debe proporcionarse información sobre por qué ciertos elementos de la información recolectada no fueron incluidos en el dataset o en un fichero de datos específico."
  },

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +15 to +35
const { guestbook, isLoadingGuestbook } = useGetGuestbookById({
guestbookRepository,
guestbookId: dataset?.guestbookId as number
})
const hasGuestbook = guestbook !== undefined

return (
<>
<Row className={styles['dataset-terms-row']} data-testid="dataset-guestbook-section">
<Col sm={3}>
<strong>{t('termsTab.guestbookTitle')} </strong>
<QuestionMarkTooltip placement="right" message={t('termsTab.guestbookTip')} />
</Col>
<Col>
{!guestbook ? (
<p
className={styles['community-norms-text']}
data-testid="dataset-guestbook-empty-message">
<Trans
t={t}
i18nKey="termsTab.noGuestbookAssigned"
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DatasetGuestbook currently decides between the “no guestbook assigned” text vs details based on guestbook being undefined. While the guestbook request is loading (or if it errors), guestbook is also undefined, so users may see the empty-state message even when a guestbook is assigned. Render a loading spinner when dataset?.guestbookId is set and isLoadingGuestbook is true, and render an error alert when errorGetGuestbook is set, instead of falling back to the empty-state copy.

Copilot uses AI. Check for mistakes.
Comment on lines +38 to 74
const handleDownloadClick = (event: MouseEvent<HTMLElement>) => {
if (!hasGuestbook || downloadDisabled) {
return
}

event.preventDefault()
setShowDownloadWithGuestbookModal(true)
}

const handleCloseGuestbookModal = () => {
setShowDownloadWithGuestbookModal(false)
}

return (
<>
{!type.originalFormatIsUnknown && (
<DropdownButtonItem href={downloadUrls.original} disabled={downloadDisabled}>{`${
type.original || ''
} (${t('actions.accessFileMenu.downloadOptions.options.original')})`}</DropdownButtonItem>
<DropdownButtonItem
href={hasGuestbook ? undefined : downloadUrls.original}
onClick={handleDownloadClick}
disabled={downloadDisabled}>{`${type.original || ''} (${t(
'actions.accessFileMenu.downloadOptions.options.original'
)})`}</DropdownButtonItem>
)}
<DropdownButtonItem href={downloadUrls.tabular} disabled={downloadDisabled}>
<DropdownButtonItem
href={hasGuestbook ? undefined : downloadUrls.tabular}
onClick={handleDownloadClick}
disabled={downloadDisabled || !downloadUrls.tabular}>
{t('actions.accessFileMenu.downloadOptions.options.tabular')}
</DropdownButtonItem>
{type.original !== FileTypeToFriendlyTypeMap['application/x-r-data'] && (
<DropdownButtonItem href={downloadUrls.rData} disabled={downloadDisabled}>
<DropdownButtonItem
href={hasGuestbook ? undefined : downloadUrls.rData}
onClick={handleDownloadClick}
disabled={downloadDisabled || !downloadUrls.rData}>
{t('actions.accessFileMenu.downloadOptions.options.RData')}
</DropdownButtonItem>
)}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When a guestbook is present, all three tabular download options (original/tabular/RData) open the same DownloadWithGuestbookModal, but the submission path (submitGuestbookForDatafileDownload) has no knowledge of which option the user clicked. As a result, the post-submit download URL can’t preserve ?format=original vs ?format=RData vs default tabular, so users may receive the wrong file format. Track the selected download variant (e.g., store a format/target URL in state per menu item) and incorporate it into the signed URL used for the final download (or extend the access submission API to accept a format parameter).

Copilot uses AI. Check for mistakes.
"@faker-js/faker": "7.6.0",
"@iqss/dataverse-client-javascript": "2.0.0-alpha.85",
"@iqss/dataverse-client-javascript": "2.1.0-pr429.f4e6bd4",
"@iqss/dataverse-design-system": "*",
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependency is pinned to a PR-specific build (2.1.0-pr429.f4e6bd4). This is risky for reproducible builds since PR build tags can be moved/removed, and it makes it harder to reason about what API surface is guaranteed. Prefer upgrading to a released semver version (or a stable pre-release) once the upstream change is merged, and document/track this temporary pin if it must remain for now.

Suggested change
"@iqss/dataverse-design-system": "*",
"@iqss/dataverse-design-system": "1.0.0",

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

FY26 Sprint 17 FY26 Sprint 17 (2026-02-11 - 2026-02-25) FY26 Sprint 18 FY26 Sprint 18 (2026-02-25 - 2026-03-11) GREI Re-arch GREI re-architecture-related Project: HDV SPA Rollout Size: 20 A percentage of a sprint. 14 hours. SPA

Projects

Status: In Progress 💻

Development

Successfully merging this pull request may close these issues.

Add terms of use and guestbook to file download

3 participants